exports.init = function(player, req, resp, onHandled) {
    var user = player.user;
    do {
        if (user.smashland) {
            resp.code = 1; resp.desc = 'inited'; break;
        }

        if (user.status.level < gConfGlobal.SmashLandOpenLevel) {
            resp.code = 1; resp.desc = 'level limit'; break;
        }
        
        player.smashLandInit();
        resp.data.smashland = user.smashland;
        resp.data.role_images = user.role_images;
    } while (false);
    
    onHandled && onHandled();
}

exports.attack = function(player, req, resp, onHandled) {
    var user = player.user;
    do {
        if (isNaN(req.args.level)) {
            resp.code = 1; resp.desc = 'args invalid'; break;
        }

        if (!req.args.team || typeof(req.args.team) != 'object') {
            resp.code = 1; resp.desc = 'team invalid'; break;
        }

        var team = req.args.team;
        var level = parseInt(req.args.level);

        var smashland = user.smashland;
        if (!smashland) {
            resp.code = 1; resp.desc = 'not init'; break;
        }

        if (0 == smashland.cur_id) {
            resp.code = 1; resp.desc = 'passed'; break;
        }

        if (smashland.cur_level && smashland.cur_level != level) {
            resp.code = 1; resp.desc = 'selected'; break;
        }
        
        var smashLandLevelConf = gConfSmashLand[smashland.cur_id][level];
        if (!smashLandLevelConf) {
            resp.code = 1; resp.desc = 'level invalid'; break;
        }
        
        var needFood = smashLandLevelConf.NeedFood;
        if (user.status.food < needFood) {
            resp.code = 1; resp.desc = 'lack of food'; break;
        }
        
        var roles = user.role;
        var teamMap = {}; //{rid, pos}
        for (var pos in team) {
            pos = +pos;
            if (pos < 0 || pos >= 9) {
                continue;
            }
            
            var rid = team[pos];
            if (!roles[rid]) {
                continue;
            }

            var attr = smashland.attrs[rid];
            if (!attr || !attr.health) {
                continue;
            }

            teamMap[rid] = pos;
        }

        var teamNums = Object.keys(teamMap).length;
        if (teamNums < 1 || teamNums > 7) {
            resp.code = 1; resp.desc = 'team wrong'; break;
        }

        // 更新阵型和难度信息
        smashland.team = {};
        for (var rid in teamMap) {
            smashland.team[teamMap[rid]] = rid;
        }
        player.markDirty('smashland.team');

        if (!smashland.cur_level) {
            player.smashLandSetLevel(level, smashLandLevelConf.Factor);
        }
        
        /*
        开始战斗
        */
        var teamId = smashland.enemy_team[level]||1;
        var teamConf = gConfSmashLandTeam[teamId];
        var buffRankScoreFactor = 0;

        var attrBuffs = {};
        for (var buffId in smashland.buffs) {
            var buffConf = gConfSmashLandBuff[buffId];
            var buffTimes = smashland.buffs[buffId];
            addAttrValue(attrBuffs, buffConf.Attribute, buffConf.Value*buffTimes);
            buffRankScoreFactor += (buffConf.RankScoreFactor*buffTimes);
            if (buffConf.Once) {
                delete smashland.buffs[buffId];
            }
        }
        player.markDirty('smashland.buffs');

        if (attrBuffs.health) {
            var smashLandRoleAttrs = smashland.attrs;
            for (var rid in smashLandRoleAttrs) {
                var smashLandRoleAttr = smashLandRoleAttrs[rid];
                if (smashLandRoleAttr.health > 0) {
                    var addHealth = Math.floor(smashLandRoleAttr.init_health * attrBuffs.health/100);
                    smashLandRoleAttr.health = Math.min(smashLandRoleAttr.health + addHealth, smashLandRoleAttr.init_health);
                }
            }
        }

        var attacker = new Fighter();
        var defender = new Fighter();

        attacker.initWithSmashLand(player);
        attacker.addAttackBeforeFight(attrBuffs.attack);
        defender.initWithSmashLandMonster(player, teamConf, smashLandLevelConf.Factor);

        var battleReport = attacker.fight(defender);
        var atkRemainInfo = battleReport.atk_remain_info;
        var defRemainInfo = battleReport.def_remain_info;

        /*
        处理战后信息
        */
        player.costResource('food', needFood);
        resp.data.food = -needFood;
        resp.data.battle = battleReport;

        var atkRemainHealth = 0;
        for (var rid in atkRemainInfo) {
            var roleInfo = atkRemainInfo[rid];
            var roleAttr = smashland.attrs[rid];
            roleAttr.health = Math.min(roleAttr.init_health, roleInfo.health);
            roleAttr.morale = roleInfo.morale;
            atkRemainHealth += roleAttr.health;
        }
        player.markDirty('smashland.attrs');
        
        var defRemainHealth = 0;
        for (var rid in defRemainInfo) {
            defRemainHealth += defRemainInfo[rid].health;
        }
        smashland.enemy_attr.health = defRemainHealth;
        player.markDirty('smashland.enemy_attr');
        
        // 战胜处理
        if (defRemainHealth <= 0) {
            // 进入下一关
            var nextId = smashland.cur_id + 1;
            if (!gConfSmashLand[nextId]) {
                nextId = 0;
            }
            player.smashLandSetId(nextId);
            
            // 发放奖励
            var addScore = smashLandLevelConf.Score;
            smashland.score += addScore;
            player.markDirty('smashland.score');

            var coin = Math.floor(user.status.level*smashLandLevelConf.CoinFactor/2);
            smashland.coin += coin;
            player.markDirty('smashland.coin');

            var awards = [];
            for (var i = 2; i <= 2; ++i) {
                var weight = smashLandLevelConf['Weight'+i];
                var award = smashLandLevelConf['Award'+i];
                if (weight && award && common.randValue(10000) < weight) {
                    awards.push(award);
                }
            }
            resp.data.awards = player.addAwards(awards);
            player.checkEvent('SmashLandTotalScore', addScore);

            // 计算九州英雄榜积分
            if (GlobalSmashLandRank.PERIOD_MATCH == GlobalSmashLandRank.getStep()) {
                var atkInitHealth = battleReport.atk_team_health;
                var battleRoundCount = Object.keys(battleReport.rounds).length;
                var cloudScore = Math.floor(Math.min(atkRemainHealth/atkInitHealth, 1.25) *
                    (buffRankScoreFactor + 100) *
                    (smashland.score + 1350) *
                    smashLandLevelConf.RankScoreFactor /
                    (battleRoundCount + 15));
               
                var round = GlobalSmashLandRank.getRound();
                if (!smashland.cloud || smashland.cloud.round != round) {
                    smashland.cloud = {
                        round: round,
                        todayScore: 0,
                        highestScore: 0,
                    }
                }

                smashland.cloud.todayScore += cloudScore;
                if (smashland.cloud.todayScore > smashland.cloud.highestScore) {
                    smashland.cloud.highestScore = smashland.cloud.todayScore;
                    var cloudQuery = {mod:'smashland', act:'updateScore', args:{round: round, score: smashland.cloud.highestScore}};
                    player.requestCloudRank(cloudQuery, {}, function() {});
                }
                player.markDirty('smashland.cloud');
                resp.data.cloud = {score: cloudScore};
            }
        }
        
        resp.data.smashland = smashland;
    } while (false);
    
    onHandled && onHandled();
}

exports.add_buff = function(player, req, resp, onHandled) {
    var user = player.user;
    do {
        var smashland = user.smashland;
        if (!smashland) {
            resp.code = 1; resp.desc = 'not init'; break;
        }

        if (isNaN(req.args.id)) {
            resp.code = 1; resp.desc = 'args invalid'; break;
        }

        var id = parseInt(req.args.id);
        var buffConf = gConfSmashLandBuff[id];
        if (!buffConf) {
            resp.code = 1; resp.desc = 'id invalid'; break;
        }
        
        var needScore = buffConf.Score;
        if (smashland.score < needScore) {
            resp.code = 1; resp.desc = 'lack of score'; break;
        }

        addAttrValue(smashland.buffs, id, 1);
        addAttrValue(smashland, 'score', -needScore);
        player.markDirty('smashland.buffs');
        player.markDirty('smashland.score');
        
        resp.data.score = -needScore;
        resp.data.buffs = smashland.buffs;
    } while (false);
    
    onHandled && onHandled();
}

exports.buy = function(player, req, resp, onHandled) {
    var user = player.user;
    do {
        var smashland = user.smashland;
        if (!smashland) {
            resp.code = 1; resp.desc = 'not init'; break;
        }

        if (isNaN(req.args.id) || isNaN(req.args.num)) {
            resp.code = 1; resp.desc = 'args invalid'; break;
        }

        var id = parseInt(req.args.id);
        var num = parseInt(req.args.num);

        if (num < 1 || num > 999) {
            resp.code = 1; resp.desc = 'invalid num'; break;
        }

        var conf = gConfSmashLandShop[id];
        if (!conf) {
            resp.code = 1; resp.desc = 'invalid id'; break;
        }

        var needCoin = conf.Price * num;
        if (smashland.coin < needCoin) {
            resp.code = 1; resp.desc = 'lack of coin'; break;
        }

        smashland.coin -= needCoin;
        player.markDirty('smashland.coin');

        var awards = [];
        var award = conf.Award1;
        if (num > 1) {
            award = clone(award);
            award[2] *= num;
        }
        awards.push(award);
        resp.data.awards = player.addAwards(awards);
        resp.data.coin = -needCoin;

    } while (false);

    onHandled && onHandled();
}

exports.save_team = function(player, req, resp, onHandled) {
    var user = player.user;
    do {
        var smashland = user.smashland;
        if (!smashland) {
            resp.code = 1; resp.desc = 'not init'; break;
        }

        var team = req.args.team;

        var roles = user.role;
        var teamMap = {}; //{rid, pos}
        for (var pos in team) {
            pos = +pos;
            if (pos < 0 || pos >= 9) {
                continue;
            }
            
            var rid = team[pos];
            if (!roles[rid]) {
                continue;
            }

            var attr = smashland.attrs[rid];
            if (!attr || !attr.health) {
                continue;
            }

            teamMap[rid] = pos;
        }
        
        var teamNums = Object.keys(teamMap).length;
        if (teamNums < 1 || teamNums > 7) {
            resp.code = 1; resp.desc = 'team wrong'; break;
        }

        smashland.team = {};
        for (var rid in teamMap) {
            smashland.team[teamMap[rid]] = rid;
        }
        player.markDirty('smashland.team');

        resp.data.team = smashland.team;
    } while (false);

    onHandled && onHandled();
}

exports.get_rank = function(player, req, resp, onHandled) {
    var user = player.user;
    do {
        var smashland = user.smashland;
        if (!smashland) {
            resp.code = 1; resp.desc = 'not init'; break;
        }

        if (GlobalSmashLandRank.PERIOD_WAIT == GlobalSmashLandRank.getStep()) {
            resp.code = 1; resp.desc = 'not open'; break;
        }

        player.requestCloudRank(req, resp, function() {
            onHandled && onHandled();
        });
        return;
    } while (false);

    onHandled && onHandled();
}

exports.get_rank_award = function(player, req, resp, onHandled) {
    var user = player.user;
    do {
        var smashland = user.smashland;
        if (!smashland) {
            resp.code = 1; resp.desc = 'not init'; break;
        }

        if (GlobalSmashLandRank.getStep() != GlobalSmashLandRank.PERIOD_AWARD) {
            resp.code = 1; resp.desc = 'time not reach'; break;
        }

        player.requestCloudRank(req, resp, function() {
            if (0 == resp.code) {
                var id = +resp.data.id;
                resp.data.awards = player.addAwards(gConfSmashLandRankAward[id].Awards);
            }
            onHandled && onHandled();
        });
        return;
    } while (false);

    onHandled && onHandled();
}
